<template>
  <div class="chat-wrapper">
    <back />
    <div class="chat-list">
      <div class="all-message">
        <span>全部消息</span>
        <el-tooltip effect="dark" content="全部已读" placement="bottom">
          <img
            class="c-p m-l-10"
            style="height: 1em"
            src="@/assets/images/all-read.png"
            alt="已读"
            @click="setAllRead"
          />
        </el-tooltip>
      </div>
      <!-- 聊天人员列表 -->
      <div
        class="chat-item"
        v-for="item in userList"
        :key="item.userId"
        :class="{ active: activeId === item.userId }"
        @click="getChatMsg(item.userId)"
      >
        <span
          v-if="
            isNotReadShouldShow(item.userId, item.message?.sender, item.message?.createTime) &&
            activeId != item.userId
          "
          class="not-read"
        >
          未读
        </span>
        <div class="chat-avatar">
          <img v-if="item.avatar" :src="item.avatar" />
          <img v-else src="@/assets/images/default-avatar.png" />
        </div>
        <div class="chat-info">
          <div class="chat-name">{{ item.nickName }}</div>
          <div class="chat-message ellipsis">{{ item.message?.content }}</div>
        </div>
        <div class="chat-time">{{ item.message?.createTime }}</div>
      </div>
      <!-- 历史聊天人员为空时展示的内容 -->
      <div v-if="!userList.length" class="not-user">无历史聊天记录</div>
    </div>
    <!-- 聊天框 -->
    <div v-show="activeId !== -1" class="chat-box">
      <div class="username">
        <span>{{ activeChat?.nickName }}</span>
        <img
          @click="onCloseChatWindow"
          class="close-img c-p"
          src="@/assets/images/close.png"
          title="关闭窗口"
          alt="关闭"
        />
      </div>
      <div ref="scrollBar" class="chat-container">
        <div ref="chatBox" class="chat-messages">
          <div
            v-for="message in chatMsg"
            :key="message.id"
            :class="{ 'my-message': message.sender !== activeId }"
            class="flex"
            style="flex-direction: column"
          >
            <span class="message-time" style="text-align: center">{{ message.createTime }}</span>
            <div class="flex message-content-box">
              <div class="message-content">{{ message.content }}</div>
            </div>
          </div>
        </div>
      </div>
      <div class="chat-input">
        <el-input
          @keyup.enter.native="sendMessage"
          v-model="message"
          placeholder="请输入聊天内容"
          resize="none"
          type="textarea"
          :rows="3"
        ></el-input>
        <el-button type="primary" @click="sendMessage">发送</el-button>
      </div>
    </div>
    <div v-show="activeId === -1" class="not-select-user">
      <img style="width: 80px" src="@/assets/images/chat.png" />
    </div>
  </div>
</template>

<script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue';
import back from '@/components/back/index.vue';
import { getHisList, getMsgList, getUserList } from '@/api/chat';
import { useWebsocketStore } from '@/store/websocket';
import { useUserStore } from '@/store/user';
import moment from 'moment';
import { SIGNAL_TYPE_ONE_TO_ONE } from '@/constants/constants';
import { getRoleKeys } from '@/utils/storage';

// 初始值为-1，不可修改，因为下面也有个-1
const activeId = ref<string | number>(-1);
const message = ref('');
const activeChat = ref();

// 当前用户是否是管理员
const isAdmin = ref(false);

// 获取历史聊天记录
const userList = ref([] as any[]);
onMounted(() => {
  const roleKeys = getRoleKeys();
  if (roleKeys?.includes('admin')) {
    isAdmin.value = true;
    getAllChatUserList();
  } else {
    getHistoryChatUserList();
  }
  // 初始化websocket
  websocket.value = websocketStore.connect();
  websocket.value.addEventListener('message', onMessage);
});
onBeforeUnmount(() => {
  // 非聊天界面时，就不需要监听了
  websocket.value?.removeEventListener('message', onMessage);
});
function getHistoryChatUserList() {
  getHisList().then((res: any) => {
    if (res.code === 200) {
      userList.value = res.data.map((item: any) => {
        return {
          ...item.user,
          message: item.message,
        };
      });
    }
  });
}
function getAllChatUserList() {
  getUserList().then((res: any) => {
    if (res.code === 200) {
      userList.value = res.data.map((item: any) => {
        return {
          ...item.user,
          message: item.message,
        };
      });
    }
  });
}
// 获取某个用户的聊天记录
const chatMsg = ref([] as any[]);
function getChatMsg(userId: number | string) {
  // 先将消息列表置空，以免切换到其他用户时，还是显示上个用户的消息
  // 但只当用户id等于当前聊天窗口的id时，才情况，否则发消息或者接受消息，都会闪屏
  if (userId != activeId.value) {
    chatMsg.value = [];
  }
  activeId.value = userId;
  activeChat.value = userList.value.find((item) => item.userId === userId);
  getMsgList(userId).then((res: any) => {
    if (res.code === 200) {
      chatMsg.value = res.data;
      updateScrollTop();
      setReadMsgTime(userId);
    }
  });
}

// 标记该用户的消息为已读，并记录当前时间，用以判断用户的消息是否已读
function setReadMsgTime(userId: number | string) {
  const curTime = moment().format('YYYY-MM-DD HH:mm:ss');
  userStore.userInfo.historyChatUserIdObj[userId] = curTime;
}

// 是否显示未读
function isNotReadShouldShow(
  userId: string | number,
  sender: string | number,
  createTime: string
): boolean {
  // 如果message为null，即双方没有聊过天，则不显示未读
  if (!sender && !createTime) {
    return false;
  }
  const readTime = userStore.userInfo.historyChatUserIdObj[userId];
  if (readTime) {
    const readTimeMS = new Date(readTime).getTime();
    const createTimeMS = new Date(createTime).getTime();
    // 当消息的创建时间大于读取时间，并且消息是对方发送的，才显示未读
    return createTimeMS > readTimeMS && userId == sender;
  } else {
    // 用户还未读取过
    return true;
  }
}

// 设置所有聊天已读
function setAllRead() {
  userList.value.forEach((item: any) => {
    setReadMsgTime(item.userId);
  });
}

// 关闭聊天窗口
function onCloseChatWindow() {
  activeId.value = -1;
}

// 控制聊天滚动条
const chatBox = ref();
const scrollBar = ref();

// 发送消息
const websocketStore = useWebsocketStore();
const userStore = useUserStore();
const websocket = ref<WebSocket>();
const sendMessage = () => {
  if (message.value.trim() === '') {
    message.value = '';
    return;
  }
  const messageObj = {
    cmd: SIGNAL_TYPE_ONE_TO_ONE,
    remoteUid: activeId.value + '',
    msg: message.value.trim(),
  };
  websocketStore.sendMessage(JSON.stringify(messageObj));
  message.value = '';
};
function updateScrollTop() {
  // 更新滚动高度
  const chatBoxHeight = chatBox.value?.scrollHeight;
  scrollBar.value.scrollTop = chatBoxHeight;
  // 等待DOM重新渲染，再次更新滚动高度
  nextTick(() => {
    const chatBoxHeight = chatBox.value?.scrollHeight;
    scrollBar.value.scrollTop = chatBoxHeight;
  });
}
// 监听服务器端发送的消息
function onMessage(event: any) {
  let msg = event.data;
  // 将指令反序列化为对象
  while (typeof msg === 'string') {
    msg = JSON.parse(msg);
  }
  const senderId = msg.remoteUid;
  const curLoginId = userStore.userInfo.userMsg?.userId;
  if (msg.cmd === 'one_to_one' && senderId == curLoginId) {
    // 自己发送消息给别人时的操作
    getChatMsg(activeId.value);
    if (isAdmin.value) {
      getAllChatUserList();
    } else {
      getHistoryChatUserList();
    }
  } else if (msg.cmd === 'one_to_one') {
    // 收到别人的消息时的回调
    if (isAdmin.value) {
      getAllChatUserList();
    } else {
      getHistoryChatUserList();
    }
    // 若当前打开的窗口是发消息的人，则获取消息，并设置消息为已读
    if (activeId.value == senderId) {
      getChatMsg(activeId.value);
      setReadMsgTime(activeId.value);
    }
  }
}
</script>

<style scoped lang="scss">
$border-color: #f0f0f0;
.chat-wrapper {
  display: flex;
  height: 500px;
  background-color: #f5f5f5;

  .chat-list {
    flex: 0 0 300px;
    background-color: #fff;
    overflow: auto;
    border-right: 1px solid $border-color;
    .all-message {
      font-size: 16px;
      padding: 15px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .chat-item {
      display: flex;
      align-items: center;
      padding: 5px 10px;
      cursor: pointer;
      transition: background-color 0.3s;
      border-top: 1px solid #f0f0f0;
      position: relative;
      .not-read {
        background-color: red;
        color: #fff;
        font-size: 12px;
        position: absolute;
        top: 0;
        right: 0;
        padding: 0 0 2px 2px;
        border-bottom-left-radius: 8px;
      }

      &:hover {
        background-color: #f5f5f5;
      }

      &.active {
        background-color: #f5f5f5;
      }

      .chat-avatar {
        margin-right: 16px;

        img {
          width: 40px;
          height: 40px;
          border-radius: 50%;
        }
      }

      .chat-info {
        flex: 1;
        overflow: hidden;

        .chat-name {
          font-size: 16px;
          font-weight: 500;
          margin-bottom: 4px;
        }

        .chat-message {
          font-size: 14px;
          color: #999;
        }
      }

      .chat-time {
        font-size: 12px;
        color: #999;
      }
    }
    .not-user {
      padding: 10px;
      text-align: center;
      border-top: 1px solid #f0f0f0;
    }
  }
  .not-select-user {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    flex: 1;
    background-color: #ffffffd7;
  }
  .chat-box {
    flex: 1;
    display: flex;
    flex-direction: column;
    background-color: #fff;
    .username {
      font-size: 16px;
      padding: 15px;
      text-align: center;
      border-bottom: 1px solid $border-color;
      position: relative;
      .close-img {
        position: absolute;
        top: 50%;
        right: 10px;
        transform: translateY(-50%);
        height: 25px;
      }
    }
    .chat-container {
      flex: 1;
      background-color: #fff;
      padding: 10px;
      overflow-y: auto;
    }

    .chat-messages {
      flex: 1;
    }

    .my-message {
      justify-content: flex-end;
    }
    .my-message .message-content-box {
      justify-content: flex-end;
    }
    .my-message .message-content {
      background-color: #1e90ff;
      color: #fff;
      padding: 8px 12px;
      border-radius: 4px;
      margin-right: 0;
      margin-left: 100px;
    }
    .message-time {
      text-align: center;
      font-size: 12px;
      color: #999;
      margin-bottom: 3px;
    }
    .message-content {
      background-color: #eee;
      color: #333;
      padding: 8px 12px;
      border-radius: 4px;
      margin-bottom: 8px;
      margin-right: 100px;
    }

    .chat-input {
      border-top: 1px solid $border-color;
      display: flex;
      align-items: flex-end;
    }
  }
}
</style>
